package com.baitiaojun.video.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baitiaojun.api.domain.user.UserInfo;
import com.baitiaojun.api.domain.video.VideoChildComment;
import com.baitiaojun.api.domain.video.VideoComment;
import com.baitiaojun.api.exception.ConditionException;
import com.baitiaojun.api.util.AESUtil;
import com.baitiaojun.api.util.ConstantUtil;
import com.baitiaojun.api.util.SnowFlakeUtil;
import com.baitiaojun.api.vo.PageInfo;
import com.baitiaojun.video.feign.ElasticsearchVideoFeign;
import com.baitiaojun.video.feign.UserFeign;
import com.baitiaojun.video.handler.RabbitMQHandler;
import com.baitiaojun.video.mapper.VideoCommentMapper;
import com.baitiaojun.video.service.VideoParentCommentService;
import com.baitiaojun.video.service.VideoService;
import com.baitiaojun.video.support.RedisSupport;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @类名 VideoCommentServiceImpl
 * @描述 TODO
 * @作者 白条君
 * @创建日期 2022/12/26 21:11
 * @版本 1.0
 */
@Service
public class VideoParentCommentServiceImpl implements VideoParentCommentService {

    @Autowired
    private VideoService videoService;

    @Resource
    private VideoCommentMapper videoCommentMapper;

    @Autowired
    private ElasticsearchVideoFeign elasticsearchVideoFeign;

    @Autowired
    private UserFeign userFeign;

    @Autowired
    private RedisSupport redisSupport;

    @Autowired
    private RabbitMQHandler rabbitMQHandler;

    @Override
    public Long addParentVideoComment(VideoComment videoComment, Long userId) throws ConditionException {
        Long videoId = videoComment.getVideoId();
        if (ObjectUtils.isEmpty(videoId)) {
            throw new ConditionException("参数异常");
        }
        Integer isExistsVideo = videoService.isExistsVideo(videoId);
        if (ObjectUtils.isEmpty(isExistsVideo)) {
            throw new ConditionException("该视频不存在");
        }
        videoComment.setId(SnowFlakeUtil.getNextId());
        videoComment.setUserId(userId);
        videoComment.setCreateTime(new Date());
        int resVideoComment = videoCommentMapper.insertSelective(videoComment);
        if (resVideoComment == 0) {
            throw new ConditionException("一级评论添加到db失败");
        }
        //发布到rabbitmq
        rabbitMQHandler.send(videoComment);
        //一级评论条数统计到redis
        String key = ConstantUtil.COMMENT_COUNT + videoId;
        Object value = redisSupport.getValue(key);
        if (ObjectUtils.isEmpty(value)) {
            redisSupport.setValue(key, 1, 1, TimeUnit.DAYS);
        } else {
            redisSupport.increment(key);
        }
        return videoComment.getId();
    }

    @Override
    public PageInfo getPageVideoCommentList(Integer pageNo, Integer pageSize, Long videoId) throws Exception {
        //判断参数异常
        if (ObjectUtils.isEmpty(videoId)) {
            throw new ConditionException("参数异常");
        }
        //判断视频是否存在
        Integer isExists = videoService.isExistsVideo(videoId);
        if (ObjectUtils.isEmpty(isExists)) {
            throw new ConditionException("该视频不存在");
        }
        //从es中每次分页的查询这个视频的20条一级评论记录是否存在（rootid为null的评论记录，通过创建时间进行倒叙排序）
        List<VideoComment> parentVideoCommentList = elasticsearchVideoFeign.getParentVideoCommentList(pageNo, pageSize, videoId);
        //如果存在，获取一级评论的id转换成set列表
        if (parentVideoCommentList.size() > 0) {
            Set<Long> ids = parentVideoCommentList.stream().map(VideoComment::getId).collect(Collectors.toSet());
            //通过一级评论的id从es中根据时间排序批量查询所有一级评论的前两条最新的二级评论
            List<VideoChildComment> childVideoCommentList = elasticsearchVideoFeign.getChildVideoCommentList(ids);
            //获取所有一级评论的userid和所有二级评论的replyuserid，并转换成set列表
            Set<Long> userIds = parentVideoCommentList.stream().map(VideoComment::getUserId).collect(Collectors.toSet());
            Set<Long> replyUserIds = childVideoCommentList.stream().map(VideoChildComment::getUserid).collect(Collectors.toSet());
            //将replyuserid合并到userid中，作为userid列表，批量查询userinfo信息
            userIds.addAll(replyUserIds);
            List<UserInfo> userInfoList = userFeign.batchGetUserInfoByUserIdsSet(userIds);
            AESUtil aesUtil = AESUtil.lazyGetAesUtil();
            for (UserInfo userInfo : userInfoList) {
                userInfo.setAvatar(aesUtil.encrypt(userInfo.getAvatar()));
            }
            //将userinfo列表转换成key为userid，value为userinfo的map集合
            Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getUserid, userInfo -> userInfo));
            //定义循环遍历中需要使用的引用
            List<VideoChildComment> videoChildCommentList;
            UserInfo parentUserInfo;
            //遍历一级评论和二级评论，如果二级评论的rootid=一级评论的id，就说明这个二级评论属于这条一级评论
            for (VideoComment parentVideoComment : parentVideoCommentList) {
                videoChildCommentList = new ArrayList<>();
                Long userid = parentVideoComment.getUserId();
                UserInfo userInfo = userInfoMap.get(userid);
                userInfo.setGender(null);
                userInfo.setFollowed(null);
                parentUserInfo = userInfo;
                for (VideoChildComment videoChildComment : childVideoCommentList) {
                    if (videoChildComment.getRootid().equals(parentVideoComment.getId())) {
                        //过滤用户信息中不需要返回的字段
                        userInfo = userInfoMap.get(videoChildComment.getUserid());
                        userInfo.setGender(null);
                        userInfo.setFollowed(null);
                        userInfo.setUserid(null);
                        userInfo.setSign(null);
                        userInfo.setCreatetime(null);
                        userInfo.setFollowing(null);
                        //对二级评论通过userid拿到userinfo，childVideoComment中进行用户信息的设置，然后添加到二级评论列表
                        videoChildComment.setUserInfo(userInfo);
                        videoChildCommentList.add(videoChildComment);
                    }
                }
                //将这条一级评论的所有二级评论添加到这个一级评论的childlist，同时进行这个一级评论的userinfo设置，另外再设置这个一级评论的二级评论总条数
                parentVideoComment.setVideoChildComments(videoChildCommentList);
                parentUserInfo.setUserid(null);
                parentUserInfo.setFollowing(null);
                parentUserInfo.setSign(null);
                parentUserInfo.setCreatetime(null);
                parentVideoComment.setUserInfo(parentUserInfo);
                parentVideoComment.setCount(videoChildCommentList.size());
            }
            //过滤一级和二级评论中不需要返回的字段
            parentVideoCommentList.forEach(videoComment -> {
                videoComment.setUserId(null);
                videoComment.setReplyUserId(null);
            });
            childVideoCommentList.forEach(videoChildComment -> {
                videoChildComment.setUserid(null);
                videoChildComment.setReplyuserid(null);
                videoChildComment.setRootid(null);
            });
        }
        return PageInfo.builder().pageList(parentVideoCommentList).size(parentVideoCommentList.size()).build();
    }

    @Transactional
    @Override
    public void removeVideoComment(Long id, Long userId) throws ConditionException {
        VideoComment videoComment = videoCommentMapper.selectVideoCommentById(id);
        if(ObjectUtils.isEmpty(videoComment)) {
            throw new ConditionException("不存在此条一级评论");
        }
        //先删除此一级评论下的所有二级评论
        videoCommentMapper.batchDeleteByRootIdAndReplyUserId(id, userId);
        //删除一级评论
        int resVideoComment = videoCommentMapper.deleteByIdAndUserId(id, userId);
        if (resVideoComment == 0) {
            throw new ConditionException("删除此条一级评论失败");
        }
    }

    @Override
    public List<VideoComment> batchVideoCommentCount(Set<Long> videoIds) {
        return videoCommentMapper.batchVideoCommentCount(videoIds);
    }

    @Override
    public Integer getVideoCommentCount(Long videoId) {
        Object commentCount = redisSupport.getValue(ConstantUtil.COMMENT_COUNT + videoId);
        if (ObjectUtils.isEmpty(commentCount)) {
            synchronized (this) {
                commentCount = redisSupport.getValue(ConstantUtil.COMMENT_COUNT + videoId);
                if (ObjectUtils.isEmpty(commentCount)) {
                    Integer count = videoCommentMapper.selectVideoCommentCount(videoId);
                    redisSupport.setValue(ConstantUtil.COMMENT_COUNT + videoId, count, 1, TimeUnit.DAYS);
                    return count;
                }
            }
        }
        return videoCommentMapper.selectVideoCommentCount(videoId);
    }

    @Override
    public Object getAppendComments(Long commentId) {
        Object appendComment = redisSupport.getValue(ConstantUtil.COMMENT_APPEND_KEY + commentId);
        if (ObjectUtils.isEmpty(appendComment)) {
            synchronized (this) {
                appendComment = redisSupport.getValue(ConstantUtil.COMMENT_APPEND_KEY + commentId);
                if (ObjectUtils.isEmpty(appendComment)) {
                    VideoComment videoComment = videoCommentMapper.selectVideoCommentById(commentId);
                    redisSupport.setValue(ConstantUtil.COMMENT_APPEND_KEY + commentId, videoComment, 1, TimeUnit.DAYS);
                    return appendComment;
                }
            }
        }
        return appendComment;
    }
}